package com.gitee.feizns.dynamic;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * <b>字符串操作工具类</b>
 *
 * @see String
 * @author feizns
 * @since 2019/6/9 0009
 */
public abstract class StringUtils {

    /**
     * <b>将字符串变为首字母大写</b>
     * @param original 原字符
     * @return 首字母大小后的字符
     */
    public static String firstUpper(String original) {
        return isEmpty(original) ? original : Character.toUpperCase(original.charAt(0)) + original.substring(1);
    }

    /**
     * <b>将字符串变为首字母小写</b>
     * @param original 原字符
     * @return 首字母小写后的字符
     */
    public static String firstLower(String original) {
        return isEmpty(original) ? original : Character.toLowerCase(original.charAt(0)) + original.substring(1);
    }

    /**
     * <b>是否非空</b>
     *
     * <p>
     *     （仅判断是否为{@code null}或者为{@code ''}）
     * </p>
     * @param str 字符串参数
     * @return 如果字符为空返回true不为空返回false
     */
    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }

    /**
     * <b>是否非空</b>
     *
     * <p>
     *     （仅判断是否为{@code null}或者为{@code ''}）
     * </p>
     * @param str 字符串参数
     * @return 如果字符为空返回false不为空返回true
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * <b>判断字符串是否为全空白</b>
     *
     * <p>
     *     （判断是否为{@code null}或者为{@code ''}或者为全空白字符串三者之一）
     * </p>
     * @param str 字符串
     * @return 如果字符为空或者是全空白字符则返回true否则返回false
     */
    public static boolean isEmptyOrBlank(String str) {
        return isEmpty(str) || str.trim().isEmpty();
    }

    /**
     * <b>判断字符串是否是非全空白</b>
     *
     * <p>
     *     （判断是否为{@code null}或者为{@code ''}或者为全空白字符串三者之一）
     * </p>
     * @param str 字符串
     * @return 如果字符为空或者是全空白字符则返回false否则返回ture
     */
    public static boolean isNotEmptyOrBlank(String str) {
        return !isEmptyOrBlank(str);
    }

    /**
     * <b>判断字符中是否包含文本</b>
     *
     * <p>
     *     （判断是否为{@code null}或者为{@code ''}或者为全空白字符串三者之一）
     * </p>
     * @param str 字符串
     * @return 如果字符为空或者是全空白字符则返回false否则返回ture
     */
    public static boolean hasText(String str) {
        return isNotEmptyOrBlank(str);
    }

    /**
     * <b>将字符串str使用predicate的规则分解为单词</b>
     * <pre>{@code
     * System.out.println(Arrays.toString(words("firstNameId", Character::isUpperCase)));//[first, Name, Id]
     * }</pre>
     * @param str 原字符
     * @return 分解后的单词数组
     */
    public static String[] words(String str, Predicate<Character> splitPredicate) {
        List<String> words = new ArrayList<>();
        int wordFirstIndex = 0;
        for (int i = 1; i < str.length(); i++) {
            if (splitPredicate.test(str.charAt(i))) {
                String word = str.substring(wordFirstIndex, i);
                words.add(word);
                wordFirstIndex = i;
            }
        }
        words.add(str.substring(wordFirstIndex));
        return words.toArray(new String[]{});
    }

    /**
     * <b>用下划线分隔单词</b>
     * <p>
     *     将原来是驼峰或者帕斯卡命名规范的字符串转成下划线命名。转下划线 （适用于帕斯卡和驼峰）
     * <p/>
     * <pre>{@code
     * //驼峰转下划线
     * System.out.println(StringUtils.toUnderline("firstName")) // "first_name"
     * //Pascal转下划线
     * System.out.println(StringUtils.toUnderline("FirstName")) // "first_name"
     * }</pre>
     * @param name 原字符串
     * @return 返回以下划线分割单词的字符串
     */
    public static String toUnderline(String name) {
        StringBuilder ret = new StringBuilder();
        int last = 0;
        for (int i = 0; i < name.length(); i++) {
            if ( Character.isUpperCase(name.charAt(i)) ) {
                ret.append(firstLower(name.substring(last, i)));
                if ( ret.length() != 0 )
                    ret.append("_");
                last = i;
            }
        }
        ret.append(firstLower(name.substring(last)));
        return ret.toString();
    }

    /**
     * <b>下划线转 Pascal</b>
     *<pre>{@code
     *     System.out.println(StringUtils.underlineToPascal("first_name")) // "FirstName"
     *}</pre>
     * @param underlineName 用下划线分隔单词的字符串
     * @return Pascal命名的字符串
     */
    public static String underlineToPascal(String underlineName) {
        StringBuilder ret = new StringBuilder();
        int last = 0;
        for (int i = 0; i < underlineName.length() && last < underlineName.length(); i++) {
            if ( underlineName.charAt(i) == '_' ) {
                ret.append(firstUpper(underlineName.substring(last, i)));
                last = i + 1;
            }
        }
        ret.append(firstUpper(underlineName.substring(last)));
        return ret.toString();
    }

    /**
     * <b>下划线转驼峰</b>
     * <pre>{@code
     *      System.out.println(StringUtils.underlineToHump("first_name")) // "firstName"
     * }</pre>
     * @param underlineName 下划线连接单词的字符串
     * @return 驼峰命名的单词字符串
     */
    public static String underlineToHump(String underlineName) {
        return firstLower(underlineToPascal(underlineName));
    }

}
